﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace jumping_on_blocks
{
    class Player
    {
        Vector3 m_position, m_legalDirections;
        private Vector3 m_velocity;
        Matrix m_rotation;
        public BoundingBox boundingBox;
        public int height; 
        public float rotationSpeed = 0.06f;
        public float moveSpeed = 0.25f;
        private float m_acceleration = 0.1f;
        private float m_maxVelocity = 0.2f;
        private float m_leftrightRot;
        private float m_updownRot;
        public Boolean isJumping;
        private float m_gravity = .01f;

        public Boolean free;

        public Vector3 Velocity
        {
            get
            {
                double x_vel = m_velocity.X * Math.Cos(m_leftrightRot) + m_velocity.Z * Math.Sin(m_leftrightRot);
                double z_vel = m_velocity.X * Math.Sin(-m_leftrightRot) + m_velocity.Z * Math.Cos(-m_leftrightRot);
                return new Vector3((float)x_vel, m_velocity.Y, (float)z_vel);
            }
        }

        public Vector3 Pos
        {
            get { return m_position; }
            set { m_position = value; }
        }

        public Matrix Rot
        {
            get { return m_rotation; }
            set { m_rotation = value; }
        }

        public float leftrightRot
        {
            get { return m_leftrightRot; }
            set
            {
                m_leftrightRot = value;
                UpdateRotation();
            }
        }

        public float updownRot
        {
            get { return m_updownRot; }
            set
            {
                m_updownRot = value;
                UpdateRotation();
            }
        }

        public Player(Vector3 startPos)
        {
            m_position = startPos;
            boundingBox = GetBounds(m_position);
            height = Block.BLOCK_SIZE * 2;
            updownRot = .001f;
        }

        public void Move(Vector3 change, Vector3 legalDirections, Boolean tcl)
        {
            m_legalDirections = legalDirections;
            //New plan. m_velocity is stored as a vector in the player's frame of reference, and transformed when retrieved or drawn.

            if (change.X == 0)
                m_velocity.X = 0;
            if (change.Z == 0)
                m_velocity.Z = 0;
     

            Vector3 newVelocity = m_velocity + change * m_acceleration;
            if (!(mag(newVelocity.X) > m_maxVelocity && mag(newVelocity.X) > mag(m_velocity.X)))
                m_velocity.X += change.X * m_acceleration;
            if (!(mag(newVelocity.Z) > m_maxVelocity && mag(newVelocity.Z) > mag(m_velocity.Z)))
                m_velocity.Z += change.Z * m_acceleration;
            if (!(mag(newVelocity.Y) > m_maxVelocity * 10 && mag(newVelocity.Y) > mag(m_velocity.Y)))
                m_velocity.Y += change.Y * m_acceleration;

            m_position += Velocity * m_legalDirections;

            if (m_legalDirections.Y == 0)
            {
                isJumping = false;
                m_velocity.Y = 0;
            }

            if (Game1.cl)
                m_velocity.Y -= m_gravity;
            else if (m_position.Y <= 2)
                m_position.Y = 2;
                
            boundingBox = GetBounds(m_position);
        }

        private float mag(float item)
        {
            return (item < 0) ? -item : item;
        }

        public BoundingBox Look(Vector3 change, Vector3 select)
        {
            Vector3 newVelocity = Velocity + change * m_acceleration;

            if(newVelocity.Y == 0)
                newVelocity.Y = m_velocity.Y - m_gravity;

            return GetBounds(m_position + newVelocity * select);
        }

        public void Update()
        {
            
            boundingBox = GetBounds(m_position);
        }

        private BoundingBox GetBounds(Vector3 position)
        {
            Vector3[] points = new Vector3[2];
            //BoundingBox has a little volume to keep you some distance away from the blocks.
            points[0] = position - Vector3.One / 2 - new Vector3(0, height / 2, 0);
            points[1] = position + Vector3.One / 2;
            return BoundingBox.CreateFromPoints(points);
        }

        private void UpdateRotation()
        {
            m_rotation = Matrix.CreateRotationX(m_updownRot) * Matrix.CreateRotationY(m_leftrightRot);
        }

        public Vector3 TransformVelocity(Vector3 velocity)
        {
            double x_vel = velocity.X * Math.Cos(m_leftrightRot) + velocity.Z * Math.Sin(m_leftrightRot);
            double z_vel = velocity.X * Math.Sin(-m_leftrightRot) + velocity.Z * Math.Cos(-m_leftrightRot);
            return new Vector3((float)x_vel, velocity.Y, (float)z_vel);
        }
    }
}
